<?php

namespace pmvc\data\validation;

use pmvc\util\StringUtil;

use UnexpectedValueException;

/**
 * Utilities for {@link Validator}s.
 */
abstract class ValidatorUtil {

	/**
	 * Chains multiple validators together to 
	 * create a single validator.  An array of
	 * validators can be passed to this function
	 * or this function can be used in a varargs
	 * manner.
	 */
	public static function chainValidator() {
		$args = func_get_args();
		if (count($args)==1 && is_array($args[0])) {
			$args = $args[0];
		}
		return new ClosureValidator(function($input)use($args) {
			foreach ($args as $validator) {
				if (is_callable($validator)) {
					$validator = new ClosureValidator($validator);
				}
				if (!$validator->validate($input)) {
					return false;
				}
			}
			return true;
		});
	}

	/**
	 * @return Validator
	 */
	public static function requiredValidator($useEmpty=false) {
		return new ClosureValidator(function($input)use($useEmpty) {
			return ($useEmpty)
				? (isset($input) && !empty($input))
				: (isset($input) && $input!='');
		});
	}

	/**
	 * @return Validator
	 */
	public static function sizeValidator($sizeMin, $sizeMax) {
		return new ClosureValidator(function($input)use($sizeMin, $sizeMax) {
			$size = -1;
			if (is_array($input)) {
				$size = count($input);
			} else if (is_string($input)) {
				$size = strlen($input);
			} else {
				throw new UnexpectedValueException();
			}
			if (isset($sizeMin) && ($size < $sizeMin)) {
				return false;
			} else if (isset($sizeMax) && ($sizeMax < $size)) {
				return false;
			}
			return true;
		});
	}

	/**
	 * @return Validator
	 */
	public static function regexValidator($pattern) {
		return new ClosureValidator(function($input)use($pattern) {
			return preg_match($pattern, strval($input)) >= 1;
		});
	}

	/**
	 * @return Validator
	 */
	public static function rangeValidator($rangeMin, $rangeMax) {
		return new ClosureValidator(function($input)use($rangeMin, $rangeMax) {
			if (isset($rangeMin) && ($input < $rangeMin)) {
				return false;
			} else if (isset($rangeMax) && ($rangeMax < $input)) {
				return false;
			}
			return true;
		});
	}

	/**
	 * @return Validator
	 */
	public static function choiceValidator(array $choices) {
		return new ClosureValidator(function($input)use($choices) {
			return in_array($input, $choices, true);
		});
	}

	/**
	 * @return Validator
	 */
	public static function arrayItemValidator(Validator $itemValidator) {
		return new ClosureValidator(function($input)use($itemValidator) {
			if (!is_array($input)) {
				throw new UnexpectedValueException();
			}
			foreach ($input as $item) {
				if (!$itemValidator->validate($item)) {
					return false;
				}
			}
			return true;
		});
	}

	/**
	 * @return Validator
	 */
	public static function matchingPropertiesValidator(Array $propertyNames, $allowNulls=false) {
		return new ClosureValidator(function($input)use($propertyNames, $allowNulls) {
			$lastVal = null;
			foreach ($propertyNames as $name) {
				$val = isset($input->$name) ? $input->$name : null;
				if (!$allowNulls && !isset($val)) {
					return false;
				} else if ($lastVal!=null && $val!=$lastVal) {
					return false;
				}
				$lastVal = $val;
			}
			return (!$allowNulls) ? $lastVal!=null : false;
		});
	}

}

?>